//
//  DebugConnection.m
//  iBasic
//
//  Created by Andrew Barry on 12/04/08.
//  Copyright 2008 Barry Computer Services. All rights reserved.
//

#import "DebugConnection.h"
#import "DebugServer.h"
#import "JavascriptProject.h"
#include <sys/socket.h>

JavascriptProject *projectForDebugKey(NSString * key) {
	JavascriptProject *doc = nil;
	NSArray *activeDocs = [[NSDocumentController sharedDocumentController] documents];
	int count = [activeDocs count];

	for (int idx = 0; idx < count; idx++) {
		doc = [activeDocs objectAtIndex:idx];
		if ([doc isMemberOfClass:[JavascriptProject class]]) {
			NSString *debugKey = [doc debugKey];
			if (debugKey != nil && [key isEqualTo: debugKey]) {
				return doc;
			}
		}
	}
	return nil;
}


@implementation DebugConnection

BOOL fullRead(int sock, void *buf, int len)
{
	unsigned char *ptr = buf;
	while (len > 0) {
		int r = read(sock, ptr, len);
		if (r <= 0)
			return NO;
		ptr += r;
		len -= r;
	}
	return YES;
}

-(void) connectionStarted: (DebugConnection *) arg
{
}

-(void) connectionEnded: (DebugConnection *) arg
{
	if (project != nil) {
		[project debugEnded: self];
		[project release];
		project = nil;
	}
}

-(void) sendPacket: (NSDictionary *) dict {
//	NSData *packet = [NSPropertyListSerialization dataFromPropertyList:dict format: NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
	NSData *packet = [NSPropertyListSerialization dataFromPropertyList:dict format: NSPropertyListXMLFormat_v1_0 errorDescription:nil];
	int32_t packLen = [packet length];
	write(i32ConnectFD, &packLen, 4);
	write(i32ConnectFD, [packet bytes], [packet length]);
	
//	printf("sent: %s\n", [packet bytes]);
}

-(void) sendCommand: (NSString *) action {
	NSMutableDictionary *dict = [NSMutableDictionary new];
	[dict setObject:action forKey:@"action"];
	[self sendPacket: dict];
}

-(void) kill {
	[self sendCommand: @"kill"];
}

-(void) gotPacket: (NSDictionary *) packet
{
	if (!connected) {
		connected = YES;

		NSString *key = [packet objectForKey:@"key"];
		bool found = false;

		NSArray *activeDocs = [[NSDocumentController sharedDocumentController] documents];
		int idx, count = [activeDocs count];
		JavascriptProject *doc = nil;
		for (idx = 0; idx < count; idx++) {
			doc = [activeDocs objectAtIndex:idx];
			if ([doc isMemberOfClass:[JavascriptProject class]]) {
				NSString *debugKey = [doc debugKey];
				if (debugKey != nil && [key isEqualTo: debugKey]) {
					found = true;
					break;
				}
			}
		}
		
		if (!found) {
			[self sendCommand: @"reject"];
		} else {
			[doc startedDebugging: self];

			project = doc;
			[project retain];
		}
	} else {
		NSString *action = [packet objectForKey:@"action"];
		if ([action isEqualToString:@"fatal"]) {
			[project debugFatalError: [packet objectForKey:@"message"]];
		} else if ([action isEqualToString:@"debugStr"]) {
			[project debugStr: [packet objectForKey:@"message"]];
		} else if ([action isEqualToString:@"debugger"]) {
			[project debugger: packet];
		}
	}
}

-(void) acceptConnection: (NSNumber *) sock
{
	NSAutoreleasePool		* pool = [[NSAutoreleasePool alloc] init];
	
	[self performSelectorOnMainThread:@selector(connectionStarted:) withObject:nil waitUntilDone:false];
		
	i32ConnectFD = [sock intValue];

	int32_t packLen;

	while (fullRead(i32ConnectFD, &packLen, 4)) {
		char *packet = malloc(packLen);
		if (!fullRead(i32ConnectFD, packet, packLen))
			break;
		NSData *data = [NSData dataWithBytes: packet length: packLen];

//		printf("received: %s\n", [data bytes]);

		
		NSString *err = nil;
		NSPropertyListFormat fmt;
		NSDictionary *debugPacket = [NSPropertyListSerialization propertyListFromData: data mutabilityOption: NSPropertyListImmutable format: &fmt errorDescription: &err];
		[self performSelectorOnMainThread:@selector(gotPacket:) withObject:debugPacket waitUntilDone:NO];
		free(packet);
	}

    shutdown(i32ConnectFD, 2);
 
    close(i32ConnectFD);

	[self performSelectorOnMainThread:@selector(connectionEnded:) withObject:nil waitUntilDone:false];

	[self release];
	[pool release];
}

@end
